package com.example.service.Impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.common.enums.KeyEnum;
import com.example.common.enums.ResultCodeEnum;
import com.example.common.exception.CustomException;
import com.example.mapper.MenuMapper;
import com.example.mapper.RoleAndMenuMapper;
import com.example.mapper.RoleMapper;
import com.example.pojo.dto.RoleDTO;
import com.example.pojo.entity.Role;
import com.example.pojo.entity.RoleAndMenu;
import com.example.pojo.entity.RouteItem;
import com.example.pojo.utils.RouteMeta;
import com.example.service.MetaService;
import com.example.service.SystemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * TODO
 *
 * @author ding
 * @since 2024/7/3
 */
@Service
@Slf4j
@DS("master")
public class SystemServiceImp implements SystemService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private MetaService metaService;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private RoleAndMenuMapper roleAndMenuMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取所有的菜单
     */
    public List<RouteItem> getAllMenu(String menuName, String status) {
        String menuString = (String) redisTemplate.opsForValue().get(KeyEnum.MENU_MANAGER);
        List<RouteItem> routeItems = (List<RouteItem>) redisTemplate.opsForValue().get(KeyEnum.MENU_MANAGER);

        if (ObjectUtil.isEmpty(routeItems)){
            //获取所有一节菜单
            routeItems = menuMapper.selectList(new LambdaQueryWrapper<RouteItem>()
                    .eq(RouteItem::getIsDeleted, 0)
                    .eq(RouteItem::getLevel, 1)
                    .like(StringUtils.hasLength(menuName), RouteItem::getMenuName, menuName)
                    .eq(StringUtils.hasLength(status), RouteItem::getStatus, status)
                    .orderByAsc(RouteItem::getOrderNo));

            for (RouteItem routeItem : routeItems) {
                //为每个父菜单设置样式
                RouteMeta parentMeat = metaService.getOne(new LambdaQueryWrapper<RouteMeta>().eq(RouteMeta::getMenuId, routeItem.getId()));
                if (ObjectUtil.isNotEmpty(parentMeat.getIsShow()) && parentMeat.getIsShow() == 1) {
                    parentMeat.setHideMenu(true);
                }
                if (ObjectUtil.isNotEmpty(parentMeat.getChildrenMenu()) && parentMeat.getChildrenMenu() == 1){
                    parentMeat.setHideChildrenInMenu(true);
                }
                routeItem.setMeta(parentMeat);

                //为父菜单设置子菜单
                List<RouteItem> childMenu = menuMapper.selectList(new LambdaQueryWrapper<RouteItem>()
                        .like(StringUtils.hasLength(menuName), RouteItem::getMenuName, menuName)
                        .eq(StringUtils.hasLength(status), RouteItem::getStatus, status)
                        .eq(RouteItem::getIsDeleted, 0)
                        .eq(RouteItem::getLevel, 2));
                Integer num = 0;
                List<Integer> childIds = new ArrayList<>();
                for (RouteItem menu : childMenu) {
                    if (routeItem.getSerial().equals(menu.getSerial().split("-")[0])){
                        num++;
                        childIds.add(menu.getId());
                    }
                }
                RouteItem[] childs = new RouteItem[num];
                for (int i = 0; i < childs.length; i++) {
                    RouteItem m = menuMapper.selectById(childIds.get(i));
                    //为每个子菜单设置样式
                    RouteMeta meta = metaService.getOne(new LambdaQueryWrapper<RouteMeta>().eq(RouteMeta::getMenuId, m.getId()));
                    if (ObjectUtil.isNotEmpty(meta.getIsShow()) && meta.getIsShow() == 1) {
                        meta.setHideMenu(true);
                    }
                    if (ObjectUtil.isNotEmpty(meta.getChildrenMenu()) && meta.getChildrenMenu() == 1){
                        meta.setHideChildrenInMenu(true);
                    }
                    if (ObjectUtil.isNotEmpty(meta.getIsKeep()) && meta.getIsKeep() == 1){
                        meta.setIgnoreKeepAlive(true);
                    }
                    m.setMeta(meta);
                    childs[i] = m;
                }
                routeItem.setChildren(childs);
            }
//            String jsonString = JSON.toJSONString(routeItems);
//            redisTemplate.opsForValue().set(KeyEnum.MENU_MANAGER, jsonString);
            redisTemplate.opsForValue().set(KeyEnum.MENU_MANAGER, routeItems);
            redisTemplate.expire(KeyEnum.MENU_MANAGER, 4, TimeUnit.HOURS);
            return routeItems;
        }else {
            List<RouteItem> MenuList = JSON.parseArray(menuString, RouteItem.class);
            return MenuList;
        }
    }

    /**
     * 获取角色信息
     * @return
     */
    public Page<Role> getRoleListByPage(String roleName, Integer status, Integer pageNum, Integer pageSize){
        Page<Role> rolePage = roleMapper.selectPage(new Page<Role>(pageNum, pageSize),
                new LambdaQueryWrapper<Role>()
                        .eq(Role::getIsDeleted, 0)
                        .like(StringUtils.hasLength(roleName), Role::getRoleName, roleName)
                        .eq(ObjectUtil.isNotEmpty(status), Role::getStatus, status)
        );

        List<Role> records = rolePage.getRecords();
        for (Role record : records) {
            List<RoleAndMenu> roleAndMenuList = roleAndMenuMapper.selectList(new LambdaQueryWrapper<RoleAndMenu>()
                    .eq(RoleAndMenu::getRoleId, record.getId()));
            record.setMenu(roleAndMenuList.stream().map(RoleAndMenu::getMenuId).collect(Collectors.toList()));
        }
        rolePage.setRecords(records);
        return rolePage;
    }

    /**
     * 设置角色状态
     */
    public void setRoleStatus(Role role) {
        roleMapper.updateById(role);
    }

    public void submitRole(RoleDTO roleDTO) {
        if (ObjectUtil.isEmpty(roleDTO.getId())){
            addRole(roleDTO);
        }else {
            updateRole(roleDTO);
        }
    }

    /**
     * 新增角色
     */
    public void addRole(RoleDTO roleDTO) {
        Role dbRole = roleMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleName, roleDTO.getRoleName()));
        if (ObjectUtil.isNotEmpty(dbRole)) {
            throw new CustomException(ResultCodeEnum.ROLE_NAME_ERROR);
        }

        Role role = new Role();
        BeanUtils.copyProperties(roleDTO,role);
        role.setVersion(0);
        role.setIsDeleted(0);
        roleMapper.insert(role);
        if (ObjectUtil.isNotEmpty(roleDTO.getMenu())) {
            List<Integer> menuList = roleDTO.getMenu();
            Integer roleId = role.getId();
            for (Integer menuId : menuList) {
                RoleAndMenu roleAndMenu = RoleAndMenu.builder()
                        .menuId(menuId)
                        .roleId(roleId)
                        .version(0)
                        .build();
                roleAndMenuMapper.insert(roleAndMenu);
            }
        }
    }

    /**
     * 更新角色
     */
    public void  updateRole(RoleDTO roleDTO) {
        List<Integer> menuList = roleDTO.getMenu();
        Role role = new Role();
        BeanUtils.copyProperties(roleDTO,role);
        roleMapper.updateById(role);

        Integer roleId = role.getId();
        roleAndMenuMapper.deleteById(new LambdaQueryWrapper<RoleAndMenu>().eq(RoleAndMenu::getRoleId, roleId));
        for (Integer menuId : menuList) {
            RoleAndMenu roleAndMenu = RoleAndMenu.builder()
                    .menuId(menuId)
                    .roleId(roleId)
                    .version(0)
                    .build();
            roleAndMenuMapper.insert(roleAndMenu);
        }
    }

    /**
     * 根据id撒谎从南湖角色信息
     */
    public void DeleteRole(Integer id) {
        Role role = roleMapper.selectById(id);
        role.setIsDeleted(1);
        roleMapper.updateById(role);
    }

}
